package com.chinamsp.dydb.configuration;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.mybatis.spring.boot.autoconfigure.MybatisProperties;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import com.alibaba.druid.util.StringUtils;
import com.chinamsp.baisc.util.ApplicationConstants;
import com.chinamsp.dydb.convert.ORMNameConverter;
import com.chinamsp.dydb.crud.BaseDao;
import com.chinamsp.dydb.dbsource.DataSourceSettings;
import com.chinamsp.dydb.dbsource.DynamicDataSource;
import com.chinamsp.dydb.mybatis.DynamicMapperSqlSessionBean;

@AutoConfigureAfter({MybatisProperties.class, DataSourceSettings.class})
@MapperScan(basePackages = ApplicationConstants.SCAN_PACKAGE_NAME, markerInterface = BaseDao.class)
public class MyBatisSqlSessionFactoryConfigration {
	
	@Bean
	@Primary
	public SqlSessionFactory sqlSessionFactory(DataSourceSettings properties, DataSource dynamicDataSource, ORMNameConverter converter) throws Exception {
		String packageStr = properties.getScanPackages();
		String[] packages;
		if (StringUtils.isEmpty(packageStr)) {
			packages = new String[] {ApplicationConstants.SCAN_PACKAGE_NAME};
		} else {
			String[] pl = packageStr.split("\\,");
			packages = new String[pl.length + 1];
			for (int i = 0;i < pl.length ;i ++) {
				packages[i] = pl[i];
			}
			packages[pl.length] = ApplicationConstants.SCAN_PACKAGE_NAME;
		}
		
		SqlSessionFactoryBean sqlSessionFactoryBean = new DynamicMapperSqlSessionBean(converter, packages);
		// 指定数据源(这个必须有，否则报错)
		sqlSessionFactoryBean.setDataSource(dynamicDataSource);
		// 下边两句仅仅用于*.xml文件，如果整个持久层操作不需要使用到xml文件的话（只用注解就可以搞定），则不加
		Resource[] mybatis = new PathMatchingResourcePatternResolver().getResources(CONFIG_LOCATION);
		if (mybatis != null) {
			sqlSessionFactoryBean.setConfigLocation(mybatis[0]);
		}
		// 加载
		List<Resource> locations = new ArrayList<Resource>(64);
		// 扫描  公共mapper
		Resource[] mappers = new PathMatchingResourcePatternResolver().getResources(COMMON_MAPPER);
		if (mappers != null && mappers.length > 0) {
			locations.addAll(Arrays.asList(mappers));
		}
		// 逐个扫描 base package
		for (String pk : packages) {
			mappers = new PathMatchingResourcePatternResolver().getResources(LOCATION_MAPPERS.replace("replace", pk.replaceAll("\\.", "/")));
			if (mappers != null && mappers.length > 0) {
				locations.addAll(Arrays.asList(mappers));
			}
		}
		
		mybatis = new Resource[locations.size()];
		locations.toArray(mybatis);
		sqlSessionFactoryBean.setMapperLocations(mybatis);
		return sqlSessionFactoryBean.getObject();
	}
	
	/**
	 * 配置事务管理器
	 */
	@Bean
	@Primary
	public DataSourceTransactionManager transactionManager(DynamicDataSource dataSource) throws Exception {
		return new DataSourceTransactionManager(dataSource);
	}
	
	/**
	 * 本地 mapper 扫描，需要被替换
	 */
	private static final String LOCATION_MAPPERS = "classpath*:replace/**/*-mapper.xml";
	
	/**
	 * 公共 mapper，只扫描一次
	 */
	private static final String COMMON_MAPPER = "classpath*:common-mapper.xml";
	
	/**
	 * mybatis 配置文件
	 */
	private static final String CONFIG_LOCATION = "classpath:mybatis.xml";
	
}
